ItIron2023
react
昨天我們配合了兩個hook去理解react render的機制以及一些useState & useEffect的眉眉角角,其中我們有提到利用物件作為state初始值的情況,今天我們就針對這一點來看一個實務常見的情況吧!
馬上就開始吧,請觀察這個codesandbox內的程式碼。
首先,這份程式碼並沒有任何的錯誤發生,所有的行為也如我們預期,輸入後點擊送出可以看到state有正確的被更新,要送出的payload並沒有任何不對,不過仔細看一下程式碼的部分你會發現有許多重複的部分,這還只是僅有三個欄位的情況,現實的userData往往更為複雜,若你每個編輯表單都要這樣搞,我相信會有許多很有趣的事情發生,請觀察以下的程式碼並優化,你的解法有著以下的前提
export default function App() {
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const [age, setAge] = useState("");
const handleNameChange = (e) => {
setName(e.target.value);
};
const handleEmailChange = (e) => {
setEmail(e.target.value);
};
const handleAgeChange = (e) => {
setAge(e.target.value);
};
const handleSubmit = () => {
console.log("Submitted User Info:", { name, email, age });
};
return (
<div className="App">
<h1>Way too many state in a component</h1>
<form>
<label>
Name:
<input type="text" value={name} onChange={handleNameChange} />
</label>
<br />
<label>
Email:
<input type="email" value={email} onChange={handleEmailChange} />
</label>
<br />
<label>
Age:
<input type="text" value={age} onChange={handleAgeChange} />
</label>
<br />
<button type="button" onClick={handleSubmit}>
Submit
</button>
</form>
</div>
);
}
這次的問題也是很常見到的情況,多半會出現在表單的新增或是編輯,比方說使用者的註冊或是偏好的更新等等。當然你完全不處理也是沒問題的,畢竟它並沒有真的造成什麼大問題,但就像我說的,要是欄位不斷增加,你整個程式碼的可讀性自然會變得更差一些。
很多人看到這個問題首先的想法就是先針對state下手,畢竟題目都說了Way too many state,所以第一步會是先用一個更大包的物件來處理,比方說userInfo這樣的state
const [userInfo, setUserInfo] = useState({ name: '', email: '', age: '' });
這樣的方向是完全正確的,但問題在於後續的onChange handler處理,如果你還是一個一個hanlder去處理每一個input欄位,例如像是這樣
const handleNameChange = () => {
setUserInfo({
...userInfo,
name: 'John'
});
};
const handleEmailChange = () => {
setUserInfo({
...userInfo,
email: 'john@example.com'
});
};
const handleAgeChange = () => {
setUserInfo({
...userInfo,
age: '30'
});
};
那麼實際上在欄位增加時你還是需要土法煉鋼去加上一個新的handler,並不是這麼理想,我個人會建議如果你要使用useState處理這類的情況,可以統一用一個handler處理,這麼一來欄位增加時也可以用更簡易的方式處理,例如像是這樣的統一hanlder
const handleChange = (e) => {
const { name, value } = e.target;
setUserInfo({
...userInfo,
[name]: value
});
};
在上方的例子中我們利用了動態的key值去處理,在此之前我們需要在原本的html結構上做一些調整,在每個input欄位加入對應的name attribute,這麼一來就可以在handler中取得需要的值作為動態key囉!
以email為例,原本是這樣的東西
<input type="email" value={email} onChange={handleEmailChange} />
你就必須動點手腳加上對應的name attribute以及修改value的傳遞方式,畢竟統一管理的話會變成使用userInfo
這樣的欄位。
<input type="email" name="email" value={userInfo.email} onChange={handleChange} />
當然,若你今天的資料更為複雜一些且在某些情況下彼此依賴,那useState就不會是最適合的解法,這個問題我們就留到下次再討論吧!
今天我們延伸了之前提過的useState以物件做初始值的情況並帶出了另一個實務上常見的問題,這類的情況很常出現在表單或是較為複雜的組件中,盡可能地去有效管理你的state可以大幅增加你程式碼可讀性並避免一些維護上的問題,但這並不是告訴你所有的state都需要用一個大物件統一管理,我們之後會再探討類似的情況,今天就先到此為止!明天見!
本文章同步發布於個人部落格,有興趣的朋友也可以來逛逛~!
作者您好
中間在統一hanlder的部分我看不太懂
上下不太連貫
這樣的統一hanlder
const handleChange = (e) => {
const { name, value } = e.target;
setUserInfo({
...userInfo,
[name]: value
});
};
下面修改html的結構是不是就要寫成
<input type="text" name="name" value={userInfo.name} onChange={handleChange}/>
lijun 你說得完全正確~這部分確實是我打得太過於簡略了,我當時的想法僅是打算跟讀者表示說需要去修改下方input欄位的程式碼,因此沒有提供修改後程式碼的樣子,不好意思!希望沒有造成你太多的困惑,我稍後會做修改,謝謝你提出!